#include "ModbusServer.h"
#include <QDebug>
#include <QMutexLocker>
#include <FloraLogger.h>
#include <modbus.h>

//当qt运行出现以下信息时

//[LspTrace]ReadAccConfig returns false!

//[LspTrace]FindMatchingProvider: inInfo is one of the LSPs entry.
//[LspTrace]WSPStartup end: 0, protocol=6



//解决方法

//通过命令提示符修复LSP
//1、打开电脑，进入命令提示符窗口，快捷键win+r.

//2、在窗口中输入“cmd”进入命令符窗口。

//3、在窗口中输入：输入netsh winsock reset，然后按下回车键。

//4、然后稍等片刻，出现提示，重启电脑即可。



ModbusServer::ModbusServer(int startAddress)
    : modbusContext(nullptr), mbMapping(nullptr), serverType(-1), serverPort(0), baudRate(0), slaveId(1), startAddress(startAddress)
{
    run_flag = false;
    mbMapping = modbus_mapping_new_start_address(0, 65535, 0, 65535, 0, 65535, 0, 65535);
}

ModbusServer::~ModbusServer()
{
     run_flag = false;
    mutex.lock();
     quit();  // 停止线程
     mutex.unlock();
     wait();  // 等待线程结束


}

void ModbusServer::startTcpServer(const QString& address, int port, int slaveId)
{
    serverType = 0;
    serverAddress = address;
    serverPort = port;
    this->slaveId = slaveId;
    run_flag = true;
    start();
}

void ModbusServer::startSerialServer(const QString& device, int baudRate, int slaveId)
{
    serverType = 1;
    serialDevice = device;
    this->baudRate = baudRate;
    this->slaveId = slaveId;
    startAddress = 0;

    run_flag = true;
    start();
}

void ModbusServer::setHoldingRegister(uint16_t address, uint16_t value)
{
    QMutexLocker locker(&mutex);

    if (address >= startAddress && address < startAddress + mbMapping->nb_registers) {
        mbMapping->tab_registers[address - startAddress] = value;
        LOG_INFO(QString("Set holding register at address %1 to value %2").arg(address).arg(value));
    }
}

void ModbusServer::setFloatHoldingRegister(uint16_t address, float value)
{
    QMutexLocker locker(&mutex);
    if (address >= startAddress && address + 1 < startAddress + mbMapping->nb_registers) {
        modbus_set_float_dcba(value, mbMapping->tab_registers + (address - startAddress));
        LOG_INFO(QString("Set float holding register at address %1 to value %2").arg(address).arg(value));
    }
}

uint16_t ModbusServer::getHoldingRegister(uint16_t address)
{
    QMutexLocker locker(&mutex);
    if (address >= startAddress && address < startAddress + mbMapping->nb_registers) {
        return mbMapping->tab_registers[address - startAddress];
    }
    return 0;
}

float ModbusServer::getFloatHoldingRegister(uint16_t address)
{
    QMutexLocker locker(&mutex);
    if (address >= startAddress && address + 1 < startAddress + mbMapping->nb_registers) {
        return modbus_get_float_dcba(mbMapping->tab_registers + (address - startAddress));
    }
    return 0.0f;
}

void ModbusServer::setCoil(uint16_t address, bool value)
{
    QMutexLocker locker(&mutex);
    if (address >= startAddress && address < startAddress + mbMapping->nb_bits) {
        mbMapping->tab_bits[address - startAddress] = value ? 1 : 0;
        LOG_INFO(QString("Set coil at address %1 to value %2").arg(address).arg(value ? 1 : 0));
    }
}

bool ModbusServer::getCoil(uint16_t address)
{
    QMutexLocker locker(&mutex);
    if (address >= startAddress && address < startAddress + mbMapping->nb_bits) {
        return mbMapping->tab_bits[address - startAddress] != 0;
    }
    return false;
}

void ModbusServer::parseModbusRequest(const uint8_t *query, int received)
{
    // 获取功能码
       uint8_t functionCode = query[modbus_get_header_length(modbusContext)];

       // 解析写单个保持寄存器的请求 (功能码 0x06)
       if (functionCode == 0x06) {
           // 解析起始地址
           uint16_t address = static_cast<uint16_t>(query[modbus_get_header_length(modbusContext) + 1] << 8) |
                              query[modbus_get_header_length(modbusContext) + 2];

           // 解析单个寄存器值
           uint16_t value = static_cast<uint16_t>(query[modbus_get_header_length(modbusContext) + 3] << 8) |
                            query[modbus_get_header_length(modbusContext) + 4];

           QVector<uint16_t> values;
           values.append(value);

           // 发送信号，通知寄存器被写入
           emit holdingRegisterWritten(address, 1, values);
            if(m_Enabeldebug){
                qDebug() << "Received Modbus Write Single Register Request:";
                qDebug() << "Address:" << address << "Value:" << value;
            }
       }
       // 解析写多个保持寄存器的请求 (功能码 0x10)
       else if (functionCode == 0x10) {
           // 解析起始地址
           uint16_t address = static_cast<uint16_t>(query[modbus_get_header_length(modbusContext) + 1] << 8) |
                              query[modbus_get_header_length(modbusContext) + 2];

           // 解析寄存器数量
           uint16_t length = static_cast<uint16_t>(query[modbus_get_header_length(modbusContext) + 3] << 8) |
                             query[modbus_get_header_length(modbusContext) + 4];

           QVector<uint16_t> values;
           int byteCount = query[modbus_get_header_length(modbusContext) + 5];  // 数据字节数量

           // 解析寄存器值
           for (int i = 0; i < length; ++i) {
               uint16_t value = static_cast<uint16_t>(query[modbus_get_header_length(modbusContext) + 6 + (i * 2)] << 8) |
                                query[modbus_get_header_length(modbusContext) + 6 + (i * 2) + 1];
               values.append(value);
           }

           // 发送信号，通知寄存器被写入
           emit holdingRegisterWritten(address, length, values);
           if(m_Enabeldebug){
               qDebug() << "Received Modbus Write Multiple Registers Request:";
               qDebug() << "Address:" << address << "Length:" << length;
               for (int i = 0; i < values.size(); ++i) {
                   qDebug() << "Register" << address + i << ":" << values[i];
               }
           }

       }
}

void ModbusServer::run()
{
    initModbusServer();
    msleep(2000);
    handleRequest();
    cleanupModbusServer();
}

void ModbusServer::initModbusServer()
{
    // 1. 创建 Modbus context
    if (serverType == 0) { // TCP
        modbusContext = modbus_new_tcp(serverAddress.toUtf8().constData(), serverPort);
    } else if (serverType == 1) { // RTU
        modbusContext = modbus_new_rtu(serialDevice.toUtf8().constData(), baudRate, 'N', 8, 1);
    } else {
        LOG_ERROR("Unknown server type");
        return;
    }

    if (!modbusContext) {
        LOG_ERROR("Failed to create Modbus context");
        return;
    }

    // 2. 设置从站ID
    modbus_set_slave(modbusContext, slaveId);
    if(m_Enabeldebug){
        modbus_set_debug(modbusContext,true);
    }
    // 3. 检查映射表
    if (!mbMapping) {
        LOG_ERROR("Modbus mapping is nullptr");
        modbus_free(modbusContext);
        return;
    }

    // 4. 根据类型初始化连接
    if (serverType == 0) {
        // TCP 模式
        int socket = modbus_tcp_listen(modbusContext, 1);
        if (socket == -1) {
            LOG_ERROR("Unable to listen TCP socket");
            modbus_free(modbusContext);
            return;
        }
        LOG_INFO(QString("TCP listening on %1:%2").arg(serverAddress).arg(serverPort));

        modbus_set_indication_timeout(modbusContext, 0xffffffff, 0);

        int client_socket = modbus_tcp_accept(modbusContext, &socket);
        if (client_socket == -1) {
            LOG_ERROR("Failed to accept TCP connection");
            modbus_close(modbusContext);
            modbus_free(modbusContext);
            return;
        }
        LOG_INFO("TCP client connected successfully");

    } else if (serverType == 1) {
        // RTU 模式
        if (modbus_connect(modbusContext) == -1) {
            LOG_ERROR("Failed to connect to serial device");
            modbus_free(modbusContext);
            return;
        }
        LOG_INFO(QString("RTU serial device %1 opened successfully at %2 bps")
                 .arg(serialDevice).arg(baudRate));
    }

    LOG_INFO("Modbus server initialized successfully");
}

void ModbusServer::cleanupModbusServer()
{
    if (modbusContext) {
        modbus_free(modbusContext);
        modbusContext = nullptr;
    }
    if (mbMapping) {
        modbus_mapping_free(mbMapping);
        mbMapping = nullptr;
    }
}

void ModbusServer::handleRequest()
{
    if (serverType == 0) {
        processTcpRequest();
    } else if (serverType == 1) {
        processSerialRequest();
    }
}

void ModbusServer::processTcpRequest()
{

    modbus_t *ctx = modbusContext;

    while (run_flag) {
        uint8_t query[MODBUS_TCP_MAX_ADU_LENGTH];
        int received = modbus_receive(ctx, query);
        if (received > 0) {
            parseModbusRequest(query,received);
            modbus_reply(ctx, query, received, mbMapping);

        } else {
            //LOG_ERROR(QString("Failed to receive request or client disconnected"));
        }
        msleep(3);
    }
}

void ModbusServer::processSerialRequest()
{

    modbus_t *ctx = modbusContext;
    while (run_flag) {
        uint8_t query[MODBUS_RTU_MAX_ADU_LENGTH];
        int received = modbus_receive(ctx, query);
        if (received > 0) {
            LOG_DEBUG<<"recive server data:" << received;
            parseModbusRequest(query,received);
            modbus_reply(ctx, query, received, mbMapping);
        } else {
            //LOG_ERROR(QString("Failed to receive request or client disconnected"));
        }
        msleep(3);
    }
}
